package compiller;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;

import webserver.HttpRequest;
import dao.DAO;

public class CompileCodeFromPage {

	private static final String CLASS_START_PATTERN = "import pages.*;import compiller.*;import webserver.*;import dao.*;import dao.models.*; import java.lang.*;import java.util.*; \n\n\n public class ";
	private static final String CLASS_END_PATTERN = "  implements IInvoker{@Override public Object invoke(DAO dao, HttpRequest rq){";
	private final Compiler compiller = new Compiler();
	private final AtomicLong indx = new AtomicLong();
	private final DAO dao;

	public CompileCodeFromPage(DAO dao) {
		this.dao = dao;
	}

	Map<String, Class<?>> cache = new HashMap<String, Class<?>>();

	public String invoke(String code, HttpRequest rq) throws Exception {
		Class<?> fromCache = cache.get(code);
		if (fromCache != null) {
			return invoke(rq, fromCache);
		}
		if (!code.contains("return")) {
			code += "return null;";
		}
		String name = "InvokerClass" + indx.getAndIncrement();
		String classToCompile = CLASS_START_PATTERN + name + CLASS_END_PATTERN
				+ code + "}}";
		if (compiller.doCompilation(name, classToCompile)) {
			// TODO Remove permgen leak
			Class<?> loadClass = Thread.currentThread().getContextClassLoader()
					.loadClass(name);
			cache.put(code, loadClass);
			return invoke(rq, loadClass);
		}
		return "Couldn't compile page";
	}

	private String invoke(HttpRequest rq, Class<?> loadClass)
			throws InstantiationException, IllegalAccessException, Exception {
		IInvoker i = (IInvoker) loadClass.newInstance();
		try {
			Object invokedResult = i.invoke(dao, rq);
			if (invokedResult == null) {
				return "";
			} else {
				return invokedResult.toString();
			}
		} catch (Throwable e) {
			throw new Exception(e);
		}
	}
}
